import 'dart:math' as math;
import 'package:flutter/services.dart';

/// 文本编辑结果：包含新的 [text] 与新的 [selection]。
///
/// 用于表示一次缩进/反缩进操作的产物。
class TextEditResult {
  final String text;
  final TextSelection selection;

  const TextEditResult(this.text, this.selection);
}

/// Tab/Shift+Tab 缩进服务。
///
/// 根据传入的 `text` 和 `selection`，返回缩进或反缩进后的文本内容与选区：
/// - **单点光标（折叠选区）**：
///   - Tab → 在光标处插入指定数量的空格；
///   - Shift+Tab → 删除光标所在行前的空格（最多 [tabSpaces] 个）；
/// - **多行选区**：
///   - Tab → 在每行行首插入指定数量的空格，并调整选区范围；
///   - Shift+Tab → 删除每行行首的空格（最多 [tabSpaces] 个），并调整选区范围。
class IndentService {
  const IndentService();

  /// 执行缩进或反缩进。
  ///
  /// - [text] 原始文本内容
  /// - [selection] 当前光标或选区
  /// - [outdent] 是否为反缩进（true=Shift+Tab，false=Tab）
  /// - [tabSpaces] 缩进空格数，默认 4
  ///
  /// 返回新的文本与选区 [TextEditResult]。
  TextEditResult indentOrOutdent({
    required String text,
    required TextSelection selection,
    required bool outdent,
    int tabSpaces = 4,
  }) {
    String newText = text;
    int newBase = selection.baseOffset;
    int newExtent = selection.extentOffset;

    // 工具：获取 offset 所在行的起点（行首位置）
    int lineStartOf(String t, int offset) {
      offset = offset.clamp(0, t.length);
      while (offset > 0 && t.codeUnitAt(offset - 1) != 0x0A) {
        offset--;
      }
      return offset;
    }

    // 工具：收集选区覆盖到的所有行起点（包含末尾在行首的情况）
    List<int> collectCoveredLineStarts(String t, int start, int end) {
      final s = math.min(start, end).clamp(0, t.length);
      final e = math.max(start, end).clamp(0, t.length);
      int pos = lineStartOf(t, s);
      final starts = <int>[];
      while (true) {
        starts.add(pos);
        final nl = t.indexOf('\n', pos);
        if (nl == -1) break;
        final nextStart = nl + 1;
        if (nextStart > e) break;
        pos = nextStart;
      }
      return starts;
    }

    // === Case 1: 折叠选区（单点光标） ===
    if (selection.isCollapsed) {
      final caret = selection.extentOffset.clamp(0, text.length);

      if (outdent) {
        // 反缩进：删除光标所在行前最多 [tabSpaces] 个空格
        final ls = lineStartOf(text, caret);
        int removable = 0;
        while (removable < tabSpaces &&
            ls + removable < newText.length &&
            newText.codeUnitAt(ls + removable) == 0x20) {
          removable++;
        }
        if (removable > 0) {
          newText = newText.replaceRange(ls, ls + removable, '');
          final delta = math.min(removable, caret - ls);
          final pos = caret - delta;
          return TextEditResult(
            newText,
            TextSelection.collapsed(offset: pos),
          );
        }
        // 行首没有可删的空格，保持不变
        return TextEditResult(
          newText,
          TextSelection.collapsed(offset: caret),
        );
      } else {
        // 缩进：插入空格
        final spaces = ' ' * tabSpaces;
        newText = newText.replaceRange(caret, caret, spaces);
        final pos = caret + spaces.length;
        return TextEditResult(
          newText,
          TextSelection.collapsed(offset: pos),
        );
      }
    }

    // === Case 2: 非折叠选区（多行处理） ===
    final starts = collectCoveredLineStarts(
      text,
      selection.baseOffset,
      selection.extentOffset,
    );

    if (outdent) {
      // 多行反缩进：删除每行行首的空格（最多 tabSpaces 个）
      final removedAt = <int, int>{};
      for (final ls in starts) {
        int removable = 0;
        while (removable < tabSpaces &&
            ls + removable < newText.length &&
            newText.codeUnitAt(ls + removable) == 0x20) {
          removable++;
        }
        if (removable > 0) removedAt[ls] = removable;
      }

      // 倒序删除，避免下标错位
      final sorted = removedAt.keys.toList()..sort((a, b) => b.compareTo(a));
      for (final ls in sorted) {
        final r = removedAt[ls]!;
        newText = newText.replaceRange(ls, ls + r, '');
      }

      // 调整选区下标
      for (final ls in starts) {
        final r = removedAt[ls] ?? 0;
        if (r == 0) continue;
        if (newBase >= ls) {
          final canShift = math.max(0, newBase - ls);
          newBase -= math.min(r, canShift);
        }
        if (newExtent >= ls) {
          final canShift = math.max(0, newExtent - ls);
          newExtent -= math.min(r, canShift);
        }
      }
    } else {
      // 多行缩进：每行行首插入空格
      final spaces = ' ' * tabSpaces;

      // 倒序插入，避免下标错位
      final desc = starts.toList()..sort((a, b) => b.compareTo(a));
      for (final ls in desc) {
        newText = newText.replaceRange(ls, ls, spaces);
      }

      // 调整选区下标
      for (final ls in starts) {
        if (newBase >= ls) newBase += spaces.length;
        if (newExtent >= ls) newExtent += spaces.length;
      }
    }

    return TextEditResult(
      newText,
      TextSelection(baseOffset: newBase, extentOffset: newExtent),
    );
  }
}
